/*
 * Expander.cpp
 *
 *  Created on: Jul 6, 2009
 *      Author: mlrus
 */

#include <climits>
#include <string.h>
#include "Common.h"
#include "Expander.h"
#include "ExpansionOP.h"
#include "Scrabble.h"

using std::cout;
using std::endl;

Cell *Expander::expandEndpoints(Cell* from, Cell* to, Cell *&startWord, Cell *&endWord, int direction) {
	Cell *expandLoc;
	if (direction < 0) {
		expandLoc = from + direction;
		startWord = expandLoc;
		endWord = to;
	} else {
		expandLoc = to + direction;
		startWord = from;
		endWord = expandLoc;
	}
	if (!scrabble->board.validCell(expandLoc))
		return NULL;
	if (scrabble->board.col(endWord) < scrabble->board.col(startWord))
		return NULL;
	return expandLoc;
}

uint Expander::testBoard(Cell *from, Cell *to,  Cell *expandLoc, Axis::Axis axis) {
	uint val = 0;
	scrabble->board.getEndpoints(axis, from, to);
	if (scrabble->checkWord(from, to, axis)) {
		if (scrabble->checkConstraints(expandLoc, Axis::getDual(axis))) {
			val = scrabble->board.scoreMove(expandLoc, axis);
			string *word = new string(scrabble->getWordbuffer());
			uint row = scrabble->board.row(from);
			uint col = scrabble->board.col(from);
			scrabble->addResult(*word, val, row, col, axis);

			//cout << "WORD:"<<*word<<"\n"<< scrabble->board.formatBoard() <<endl;

		}
	}
	return val;
}

int Expander::applyOperatorSequences(const Cell *cell) {
	return applyOperatorSequences(0, cell, scrabble->rack.c_str());
}

int Expander::applyOperatorSequences(const int nextExpanderIndex, const Cell *cell, const char *rack) {
	d++;
	int numInRack = strlen(rack);
	char nextRack[Common::rackSize];
	int val = INT_MIN;
	Axis::Axis axis = expansionOp->getAxis();
	Axis::Axis dual = Axis::getDual(axis);
	if (scrabble->checkConstraints(cell, dual)) {
		Cell *from, *to, *startWord, *endWord;
		scrabble->board.getEndpoints(cell, axis, from, to);

		for (int expanderIndex = nextExpanderIndex; expanderIndex < expansionOp->getNumExtensions(); expanderIndex++) {
			int direction = *(expansionOp->getExtensionDirections() + expanderIndex);
			Cell *expandLoc = expandEndpoints(from, to, startWord, endWord, direction);
			if (expandLoc != NULL && scrabble->board.hasAdjacent(expandLoc)) {
				for (int rackPos = 0; rackPos < numInRack; rackPos++) {
					uchar ch = rack[rackPos];
					if (expandLoc->validFor(ch, dual)) {
						scrabble->board.setCell(expandLoc, ch);
						testBoard(startWord, endWord, expandLoc, axis);
						if (numInRack > 1) {
							char *rPtr = nextRack;
							for (int i = 0; i < rackPos; i++)
								*rPtr++ = rack[i];
							for (int i = rackPos + 1; i < numInRack; i++)
								*rPtr++ = rack[i];
							*rPtr = 0;
							int newVal = applyOperatorSequences(nextExpanderIndex, expandLoc, nextRack);
							if (newVal > val)
								val = newVal;
							if (nextExpanderIndex < expansionOp->getNumExtensions() - 1) {
								newVal = applyOperatorSequences(nextExpanderIndex + 1, expandLoc, nextRack);
								if (newVal > val)
									val = newVal;
							}
						}
					}
					scrabble->board.retractCell(*expandLoc);
				}
			}
		}
	}
	d--;
	return val;
}
